package com.baidu.ota.impl;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;

import com.baidu.commonlib.interfaces.IDownloadListenerEx;
import com.baidu.commonlib.interfaces.IOtaAgent;
import com.baidu.commonlib.interfaces.IUpgradeListenerEx;
import com.baidu.ota.R;
import com.baidu.ota.activity.LaunchActivity;
import com.baidu.ota.application.BaseApplication;
import com.baidu.ota.interfaces.INotifyHandler;
import com.baidu.ota.meta.Strings;
import com.baidu.ota.utils.MetaData;
import com.baidu.otasdk.ota.Constants;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 默认的通知处理器
 */
public class DefaultNotifyHandler implements INotifyHandler {

    private static INotifyHandler handler;
    private final boolean uiInteract;
    private final String notifyPackage;

    DefaultNotifyHandler() {
        handler = this;

        uiInteract = MetaData.getBool(MetaData.UI_INTERACT);
        notifyPackage = MetaData.getString(MetaData.NOTIFY_PACKAGE);

        if (!uiInteract) {
            // 注册接收用户确认升级broadcast
            BaseApplication.getInst().getApplicationContext().registerReceiver(new UpgradeConfirmReceiver(),
                    new IntentFilter(Strings.USER_UPGRADED_CONFIRM_BROADCAST));
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onNewVersionNotify(String pid, String infoList) {
        Log.d(Constants.TAG, "ui interact:" + uiInteract);
        createNotification();
        if (!uiInteract) {
            // 有更新了，下载完成后发广播确认是否升级
            download(BaseApplication.getInst().getOtaAgent(pid), infoList);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private void createNotification() {
        NotificationManager notificationManager = (NotificationManager) BaseApplication.getInst().getSystemService(BaseApplication.getInst().NOTIFICATION_SERVICE);
        Intent intent = new Intent(BaseApplication.getInst(), LaunchActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(BaseApplication.getInst(), 0, intent, 0);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("002", "默认通知", NotificationManager.IMPORTANCE_DEFAULT);
            //new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH)
            notificationManager.createNotificationChannel(channel);
        }
        Notification notification = new NotificationCompat.Builder(BaseApplication.getInst(), "002")
                .setContentTitle("新系统")
                .setContentText("系统更新")
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(BaseApplication.getInst().getResources(), R.mipmap.ic_launcher))
                .setWhen(System.currentTimeMillis())
                .setContentIntent(pendingIntent)
                .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/luna.ogg")))
                .setVibrate(new long[]{0, 1000, 1000, 1000})
                .setLights(Color.GREEN, 1000, 1000)
                .setAutoCancel(true)
                .build();
        notificationManager.notify(1, notification);

    }

    @Override
    public void onUpgradedNotify(String jsonString) {
        if (uiInteract) {
            return;
        }
        if (TextUtils.isEmpty(notifyPackage)) {
            Log.d(Constants.TAG, "notify_package is null");
            return;
        }

        Intent intent = new Intent(Strings.NOTIFY_UPGRADED_BROADCAST);
        intent.setPackage(notifyPackage);
        intent.putExtra(Strings.NOTIFY_UPGRADED_INFO, jsonString);

        BaseApplication.getInst().sendBroadcast(intent);
    }

    private void notifyUpgradeConfirm(String pid, String pkg) {
        if (TextUtils.isEmpty(notifyPackage)) {
            Log.d(Constants.TAG, "notify_package is null");
            // Log.d(Constants.TAG, "notify_package is null, upgrade directly");
            // upgradeByName(pid, pkg);
            return;
        }

        Intent intent = new Intent(Strings.NOTIFY_NEW_VERSION_BROADCAST);
        intent.setPackage(notifyPackage);

        intent.putExtra(Strings.NOTIFY_NEW_VERSION_PID, pid);
        intent.putExtra(Strings.NOTIFY_NEW_VERSION_PKG, pkg);

        BaseApplication.getInst().sendBroadcast(intent);
        Log.d(Constants.TAG, "notifyUpgradeConfirm");
    }

    private void download(final IOtaAgent otaAgent, final String infoList) {
        if (otaAgent == null) {
            return;
        }

        final List<String> names = new ArrayList<>();
        try {
            JSONArray array = new JSONArray(infoList);
            for (int i = 0; i < array.length(); ++i) {
                JSONObject object = array.getJSONObject(i);
                String pkg = object.getString("package");

                if (!TextUtils.isEmpty(pkg)) {
                    names.add(pkg);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        final int s = names.size();
        Log.d(Constants.TAG, "notify download size:" + s);
        if (s <= 0) {
            return;
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (String pkg : names) {
                    MyDownloadListener listener = new MyDownloadListener();
                    otaAgent.downLoad(pkg, listener);
                    if (listener.waitResult()) {
                        notifyUpgradeConfirm(otaAgent.getProductId(), pkg);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        Log.w(Constants.TAG, "download interrupted, go next");
                    }
                }
            }
        }).start();
    }

    /**
     * 支持同步回调的基类
     *
     * @param <T> 返回结果类型
     */
    private static class SyncCallbackBaseClass<T> {
        private final CountDownLatch downLatch = new CountDownLatch(1);
        private T value;

        void setResult(T value) {
            this.value = value;
            downLatch.countDown();
        }

        T waitResult() {
            try {
                downLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return value;
        }
    }

    private static class MyDownloadListener extends SyncCallbackBaseClass<Boolean> implements IDownloadListenerEx {
        @Override
        public void onPending(String s) {
            // ignore
        }

        @Override
        public void onPrepare(String s) {
            // ignore
        }

        @Override
        public void onProgress(String s, long i, long i1) {
            // ignore
        }

        @Override
        public void onPaused(String s) {
            setResult(false);
        }

        @Override
        public void onFailed(String s, int i, String s1) {
            setResult(false);
        }

        @Override
        public void onFinished(String s) {
            setResult(true);
        }

        @Override
        public void onReplaced(String pkgName) {
            Log.w(Constants.TAG, "been replaced");
            setResult(false);
        }
    }

    private static class MyUpgradeListener implements IUpgradeListenerEx {

        private final String pid;

        MyUpgradeListener(String id) {
            pid = id;
        }

        @Override
        public boolean upgradeConfirm(int i) {
            return i == 0;
        }

        @Override
        public void onProgress(String s, String s1, int i) {
            Log.v(Constants.TAG, "upgrade progress:" + s + "," + s1 + "," + i);
        }

        @Override
        public void onFailed(String s, int i, String s1) {
            Log.w(Constants.TAG, "upgrade fail:" + s + "," + i + "," + s1);
            sendBroadcast(pid, s, false, i + ":" + s1);
        }

        @Override
        public void onWriteDone(String s) {
            Log.w(Constants.TAG, "upgrade write:" + s);
        }

        @Override
        public void onSuccess(String s) {
            Log.w(Constants.TAG, "upgrade success:" + s);
            sendBroadcast(pid, s, true, "");
        }

        private static void sendBroadcast(String pid, String pkg, boolean success, String reason) {
            try {
                JSONObject object = new JSONObject();
                object.put("result", success);
                object.put("reason", reason);
                object.put("package", pkg);
                object.put("pid", pid);

                if (handler != null) {
                    handler.onUpgradedNotify(object.toString());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private class UpgradeConfirmReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == null) {
                return;
            }

            Log.d(Constants.TAG, "receive user upgrade confirm msg");
            if (action.equals(Strings.USER_UPGRADED_CONFIRM_BROADCAST)) {
                String pid = intent.getStringExtra(Strings.USER_UPGRADED_CONFIRM_PID);
                String pkg = intent.getStringExtra(Strings.USER_UPGRADED_CONFIRM_PKG);

                upgradeByName(pid, pkg);
            }
        }
    }

    private void upgradeByName(String pid, String pkg) {
        IOtaAgent otaAgent = BaseApplication.getInst().getOtaAgent(pid);
        if (otaAgent == null) {
            Log.e(Constants.TAG, "receive upgrade with error pid");
            return;
        }
        otaAgent.upgrade(pkg, new MyUpgradeListener(pid));
    }


}
